package model;

import java.util.List;
import java.util.Observable;
import java.util.Observer;

import utils.Common;

public class Cell extends Observable implements Observer {
	
	private int abscissa;		//XX
	private int ordinate;			//YY
	private String value = null;
	private WorksheetModel model;
	
	public Cell (int abscissa, int ordinate, WorksheetModel _model) {
		this.abscissa = abscissa;
		this.ordinate = ordinate;
		this.model = _model;
	}
	
	public int getAbscissa() {
		return abscissa;
	}
	
	public int getOrdinate() {
		return ordinate;
	}
		
	public String getValue() {
				
		return this.value;
	}
	
	public void setValue(String value) {
		
		this.value = value;	
	}

	public void setObserver(Observer obs)
	{
		this.addObserver(obs);
	}
	
	@Override
	public void update(Observable o, Object arg) {
		
		Cell observableCell = (Cell)o;
		System.out.println("Handling cell: " + this.toString());
		String updatedValue = this.doMagik();		
	}
	
	public String doMagik()
	{
		String newValue = this.value;
		
		if (newValue.charAt(0) == '=') {

			newValue = newValue.substring(1);				//retira o "="
			
			List<String> operands = Common.getMatches("[A-Z]+\\d+", newValue);
			
			int[] coordinates;
			String cellResult = null;
			for (String operand : operands) {
				coordinates = Common.GetCoordinates(operand);
				
				try {
				
					cellResult = computeCellValue(coordinates);
				
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				newValue = newValue.replace(operand, cellResult);
			}
			
		}
		newValue = Integer.toString(doMath(newValue));
		
		setChanged();
		notifyObservers(newValue);
		
		return newValue;
	}
	
	private String computeCellValue()
	{
		Cell targetCell = model.getCell(abscissa, ordinate);
		targetCell.addObserver(this);
		String cellValue = targetCell.getValue(); 
		
		//se for um numero
		if (Common.isDigit(cellValue)) {
			return cellValue;
		}
		
		List<String> operands = Common.getMatches("[A-Z]+\\d+", cellValue);
		String auxCellValue;
		for (String operand : operands) {
			
			try {
			
				auxCellValue = computeCellValue(Common.GetCoordinates(operand));
				cellValue = cellValue.replace(operand, auxCellValue);
			
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
		return Integer.toString(doMath(cellValue));
	}
	
	private String computeCellValue(int[] coordinates) throws Exception
	{
		Cell targetCell = model.getCell(coordinates[0], coordinates[1]);
		targetCell.addObserver(this);
		String cellValue = targetCell.getValue(); 
		
		//se for um numero
		if (Common.isDigit(cellValue)) {
			return cellValue;
		}
		
		List<String> operands = Common.getMatches("[A-Z]+\\d+", cellValue);
		String auxCellValue;
		for (String operand : operands) {
			auxCellValue = computeCellValue(Common.GetCoordinates(operand));
			cellValue = cellValue.replace(operand, auxCellValue);
		}
		
		return Integer.toString(doMath(cellValue));
	}
	
	private int doMath(String expression) {
		
		int res = 0;
		
		List<String> parts = Common.getMatches("[\\+\\-]?\\d", expression);
		
		for (String part : parts) {
			res += Integer.parseInt(part);
		}
		
		return res;
	}
	
	@Override
	public String toString() {
		return String.format("Abscissa: %s; Ordinate: %s; Value: %s", this.getAbscissa(), this.getOrdinate(), this.getValue());
	}
}	

